--
-- Author: xuzhihui
-- Date: 2016-03-15 09:00:00
--
-- 游戏框架
local Framework = class("Framework")

function Framework:ctor()
	self._modules = {}
	self._moduleUpdates = {}
	self._moduleFixedUpdates = {}

	self._eventProcs = {}
	self._events = {}

	-- 当前累计时间
	self.now = 0

	self._moduleInit = false;
	self._moduleInitCount = 0;
	self._moduleInitCompletedCount = 0;
	self._onModuleInitCompleted = nil
end

function Framework:Dispose()
	self._moduleUpdates = nil
	
	local module = nil
	for i=1,#self._modules do
		module = self._modules[i]
		module:Dispose()
	end

	self._modules  = nil
	self._eventProcs = nil

	local evt = nil
	for i=1,#self._events do
		evt = self._events[i]
		evt.Dispose()
	end

	self._events = nil
end

-- 更新
function Framework:Update(dt)
	-- 累计时间
	self.now = self.now + dt

	self:UpdateModule(dt)
	self:UpdateEvent(dt)
end

-- 定时更新
function Framework:FixedUpdate(dt)
	self:FixedUpdateModule(dt)
end

function Framework:ServerTime()
	if not self._timeCtrl then
		local gametop = gModuleMgr.getObject("gametop")
    	self._timeCtrl = gametop.playertop_:getModule("timeCtrl")
	end
    return self._timeCtrl:getServerTime()
end

-- 初始化所有模块
function Framework:InitModules(onModuleInitCompleted, late)
	late = late or false

	self._moduleInit = true
	self._moduleInitCount = 0
	self._moduleInitCompletedCount = 0
	self._onModuleInitCompleted = onModuleInitCompleted

	for k, v in ipairs(self._modules) do
		if not late then
			if not v._init then
				self._moduleInitCount = self._moduleInitCount + 1
				v:Init(handler(self, self.OnModuleInitCompleted))
			end
		else
			if not v._initLate then
				self._moduleInitCount = self._moduleInitCount + 1
				v:LateInit(handler(self, self.OnModuleInitCompleted))
			end
		end
	end

	self._moduleInit = false
	self:CheckModuleInit()
end

-- 模块初始化完成
function Framework:OnModuleInitCompleted(module)
	self._moduleInitCompletedCount = self._moduleInitCompletedCount + 1

	if not self._moduleInit then
		self:CheckModuleInit()
	end
end

-- 检测模块是否初始化完成
function Framework:CheckModuleInit()
	if self._moduleInitCompletedCount == self._moduleInitCount then
		if self._onModuleInitCompleted then
			self._onModuleInitCompleted()
		end
	end
end

-- 调用模块清除数据
function Framework:ModulesClear(isLogout)
	-- 这边使用逆序
	for i=#self._modules,1,-1 do
		self._modules[i]:Clear(isLogout)
	end
end

-- 注册模块
function Framework:AddModule(module)
	for k, v in ipairs(self._modules) do
		if v == module then
			return
		end
	end

	table.insert(self._modules, module)
end

-- 移除模块
function Framework:RemoveModule(module)
	for k, v in ipairs(self._modules) do
		if v == module then
			table.remove(self._modules, k)
			break
		end
	end
end

-- 根据模块名获得指定模块
function Framework:FindModule(name)
	local module = nil
	for k, v in ipairs(self._modules) do
		if v.__cname == name then
			module = v
			break
		end
	end

	return module
end

-- 注册模块更新
function Framework:AddUpdate(module, priority)
	for k, v in ipairs(self._moduleUpdates) do
		if v.data == module then
			return
		end
	end

	if not priority then
		priority = 1
	end

	local pos = 1
	for k, v in ipairs(self._moduleUpdates) do
		if v.priority > priority then
			break
		end

		pos = pos + 1
	end

	table.insert(self._moduleUpdates, pos, {data = module, priority = priority})
end

-- 移除模块更新
function Framework:RemoveUpdate(module)
	for k, v in ipairs(self._moduleUpdates) do
		if v.data == module then
			table.remove(self._moduleUpdates, k)
			break
		end
	end
end

-- 更新模块
function Framework:UpdateModule(dt)
	for k, v in ipairs(self._moduleUpdates) do
		v.data:Update(dt)
	end
end

-- 注册模块固定更新
function Framework:AddFixedUpdate(module, priority)
	for k, v in ipairs(self._moduleFixedUpdates) do
		if v.data == module then
			return
		end
	end

	if not priority then
		priority = 1
	end

	local pos = 1
	for k, v in ipairs(self._moduleFixedUpdates) do
		if v.priority > priority then
			break
		end

		pos = pos + 1
	end

	table.insert(self._moduleFixedUpdates, pos, {data = module, priority = priority})
end

-- 移除模块固定更新
function Framework:RemoveFixedUpdate(module)
	for k, v in ipairs(self._moduleFixedUpdates) do
		if v.data == module then
			table.remove(self._moduleFixedUpdates, k)
			break
		end
	end
end

-- 更新模块
function Framework:FixedUpdateModule(dt)
	for k, v in ipairs(self._moduleFixedUpdates) do
		v.data:FixedUpdate(dt)
	end
end

--[[ 注册事件处理
@param eventId 	事件ID
@param callee	回调函数所在的类对象
@param func 	回调函数

可以有以下两种注册方式
1,注册类的事件函数处理
me.framework:registerEventProc(EventId.Test, self, self.testFunc)

2,注册全局事件函数处理
me.framework:registerEventProc(EventId.Test, nil, globalTestFunc)

例:
local ModuleBase = require("framework.ModuleBase")
local FirstModule = class("FirstModule", ModuleBase)

function FirstModule:ctor()
	FirstModule.super.ctor(self, "FirstModule")

	-- 注册事件
	me.framework:AddEventProc(EventId.Test, self, self.testFunc)
	me.framework:AddEventProc(EventId.Test, nil, globalTestFunc)

	-- 移除事件
	me.framework:RemoveEventProc(EventId.Test, self, self.testFunc)
	me.framework:RemoveEventProc(EventId.Test, nil, globalTestFunc)
end

function FirstModule:testFunc(event)
	printf("FirstModule:TestFunc, %d", event.eventId)
end

function globalTestFunc(event)
	printf("GlobalTestFunc, %d", event.eventId)
end
]]
function Framework:AddEventProc(eventId, callee, func)
	if self._eventProcs[eventId] == nil then
		self._eventProcs[eventId] = {}
	end

	local procs = self._eventProcs[eventId]
	for i,v in ipairs(procs) do
		if v.callee == callee and v.func == func then
			return
		end
	end

	table.insert(procs, {callee = callee, func = func})
end

--[[ 移除事件处理
@param eventId 	事件ID
@param callee	回调函数所在的类对象
@param func 	回调函数
]]
function Framework:RemoveEventProc(eventId, callee, func)
	local procs = self._eventProcs[eventId]
	if procs == nil then
		return
	end

	for i,v in ipairs(procs) do
		if v.callee == callee and v.func == func then
			table.remove(procs, i)
			break
		end
	end
end

--[[同步事件
@param event 	事件
]]
function Framework:SendEvent(event)
	local procs = self._eventProcs[event.eventId]
	if procs == nil then
		return
	end

	-- 这边浅拷贝一份,避免在事件处理函数中移除
	procs = table.slice(procs)
	for i,v in ipairs(procs) do
		if v.func ~= nil then
			if v.callee ~= nil then
				v.func(v.callee, event)
			else
				v.func(event)
			end
		end
	end

	procs = nil

	-- 清理
	event:Dispose()
	event = nil
end

--[[异步事件
@param event 	事件
@param delay 	延后(s)
]]
function Framework:PostEvent(event, delay)
	if not delay then
		delay = 0
	end

	table.insert(self._events, {event = event, time = self.now, delay = delay})
end

function Framework:UpdateEvent(dt)
	local count = #self._events
	if count > 0 then
		local index = 1
		local info = nil

		while index <= count do
			info = self._events[index]
			-- 时间到达
			if info.time + info.delay <= self.now then
				-- 先移除,避免触发的时候异常导致重复触发
				table.remove(self._events, index)

				-- 触发
				self:SendEvent(info.event)
			else
				index = index + 1
			end
		end
	end
end

return Framework